#pragma once

#include <QAbstractTableModel>
#include "actualizable.h"
#include <assert.h>

template<class T> class ModeloDatosGenerico : public QAbstractTableModel
{
public:
    ModeloDatosGenerico(QObject *parent = 0) : QAbstractTableModel(parent) {
        listaDatos = NULL;
        listaPunterosDatos = NULL;
    }
    virtual ~ModeloDatosGenerico() { }

    void limpiar() {
        listaTitulosCampos.clear();
        listaNombresCampos.clear();
    }

    void agregarCampo(QString titulo, QString nombreCampo) {
        listaTitulosCampos.append(titulo);
        listaNombresCampos.append(nombreCampo);
    }

    void setListaDatos(QList<T>* listaDatos) {
        this->listaDatos = listaDatos;
        this->listaPunterosDatos = NULL;
    }

    void setListaDatos(QList<T*>* listaPunterosDatos) {
        this->listaDatos = NULL;
        this->listaPunterosDatos = listaPunterosDatos;
    }

    void actualizar() {
		layoutAboutToBeChanged();
        emit layoutChanged();
    }

    T obtenerElemento(int i) const {
        assert(i >= 0 && i < getNumeroFilas());
        if (listaDatos != NULL) {
            return listaDatos->at(i);
        } else if (listaPunterosDatos != NULL) {
            return *(listaPunterosDatos->at(i));
        } else {
            return T();
        }
    }

    QString nombreColumna(int i) const {
        assert(i >= 0 && i < listaNombresCampos.size());
        return listaNombresCampos.at(i);
    }
    
    QVariant data(const QModelIndex& index, int role) const {
        if (!index.isValid() || role != Qt::DisplayRole) {
            return QVariant();
        }

        int fila = index.row();
        if (fila < 0 || fila > getNumeroFilas()) {
            return QVariant();
        }

        if (listaDatos != NULL) {
            const T& datos = listaDatos->at(fila);
            return datos.get(nombreColumna(index.column()));
        } else if (listaPunterosDatos != NULL){
            T* datos = listaPunterosDatos->at(fila);
            return datos->get(nombreColumna(index.column()));
        } else {
            return QVariant();
        }
    }

    QVariant headerData(int section, Qt::Orientation orientation, int role) const {
        if (orientation == Qt::Vertical) {
            return QString::number(section);
        }

        if (role == Qt::DisplayRole && section >= 0 && section < listaTitulosCampos.size()) {
            return listaTitulosCampos.at(section);
        }
        return QVariant();         
    }

    int getNumeroFilas() const {
        if (listaDatos != NULL) {
            return listaDatos->size();
        } else if (listaPunterosDatos != NULL) {
            return listaPunterosDatos->size();
        } else {
            return 0;
        }
    }

    int getNumeroColumnas() const {
        return listaNombresCampos.size();
    }

    int columnCount(const QModelIndex& parent) const {
        return getNumeroColumnas();
    }

    int rowCount(const QModelIndex& parent) const { 
        return getNumeroFilas();
    }

    void subirElemento(int indice) {
        if (listaDatos == NULL || indice < 1 || indice >= getNumeroFilas()) {
            return;
        }
        if (listaDatos != NULL) {
            listaDatos->move(indice, indice - 1);
        } else if (listaPunterosDatos != NULL) {
            listaPunterosDatos->move(indice, indice - 1);
        }
    }

    void bajarElemento(int indice) {
        if (listaDatos == NULL || indice < 0 || indice >= getNumeroFilas() - 1) {
            return;
        }
        if (listaDatos != NULL) {
            listaDatos->move(indice, indice + 1);
        } else if (listaPunterosDatos != NULL) {
            listaPunterosDatos->move(indice, indice + 1);
        }
    }

private:
    QList<T>* listaDatos;
    QList<T*>* listaPunterosDatos;

    QList<QString> listaTitulosCampos;
    QList<QString> listaNombresCampos;
};


